package com.zh.mycommon.util;

import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.stream.Stream;

/**
 * 文件工具
 *
 * @author ZH
 * @date 09:58 2023/7/10
 */
public final class MyFileUtil {
    public static final int DATA_KB = 1 << 10; //1024
    public static final int DATA_MB = 1 << 20;
    public static final long DATA_GB = 1 << 30;


    /**
     * 计算文件的md5值
     *
     * @param file 文件
     * @return md5值
     */
    public static String fileMD5(@NotNull File file) {
        try {
            return fileMD5(new FileInputStream(file));
        } catch (FileNotFoundException e) {
            throw new IllegalArgumentException(e.getMessage());
        }
    }

    /**
     * 计算文件的md5值
     *
     * @param inputStream 文件输入流，方法执行完后，stream会被close
     * @return md5值
     */
    public static String fileMD5(@NotNull InputStream inputStream) {
        try (inputStream) {
            MessageDigest md5 = MessageDigest.getInstance("MD5");

            final byte[] digest;

            byte[] buffer = new byte[DATA_MB];
            int length;
            while ((length = inputStream.read(buffer)) != -1) {
                md5.update(buffer, 0, length);
            }
            digest = md5.digest();

            StringBuilder sb = new StringBuilder();
            for (byte b : digest) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();

        } catch (NoSuchAlgorithmException | IOException ex) {
            throw new IllegalArgumentException(ex);
        }
    }


    /**
     * 计算文件的大小
     *
     * @param file 文件
     * @return 文件大小(b)
     */
    public static long sizeOfFile(@NotNull File file) {
        if (file.isDirectory()) {
            throw new IllegalArgumentException(file + "无法计算directory的size");
        }
        try {
            return Files.size(file.toPath());
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 计算目录的大小
     *
     * @param directory
     * @return
     */
    public static long sizeOfDirectory(@NotNull File directory) {
        if (!directory.isDirectory()) {
            throw new IllegalArgumentException("必须是directory");
        }

        File[] files = directory.listFiles();
        if (files == null) return 0;

        long size = 0;

        for (File file : files) {
            if (file.isDirectory()) {
                size += sizeOfDirectory(file);
            } else {
                try {
                    size += Files.size(file.toPath());
                } catch (IOException e) {
                    throw new RuntimeException("计算file size时出现异常. " + e.getMessage());
                }
            }
        }
        return size;
    }

    /**
     * 删除目录
     *
     * @param directory 目录
     */
    public static boolean deleteDirectory(@NotNull Path directory) {
        try (Stream<Path> walk = Files.walk(directory)) {
            walk.sorted(Collections.reverseOrder())
                    .map(Path::toFile)
                    .forEach(File::delete);
            return true;
        } catch (Exception e) {
            System.out.println("删除时出现异常, err = " + e.getMessage());
            return false;
        }
    }


    // 格式化文件大小
    public static String formatSize(long size) {
        var units = new String[]{"B", "KB", "MB", "GB", "TB"};
        var index = 0;

        var number = (double) size;

        while (number >= 1024 && index < units.length - 1) {
            number /= 1024;
            index++;
        }
        return String.format("%.2f %s", number, units[index]);
    }
}

